package com.dt.platform.ops.service.impl;

import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSONObject;
import com.dt.platform.domain.ops.MonitorNode;
import com.dt.platform.domain.ops.MonitorTplIndicator;
import com.dt.platform.ops.service.IMonitorAlertService;
import com.dt.platform.ops.service.IMonitorTplTriggerService;
import com.github.foxnic.commons.busi.id.IDGenerator;
import com.github.foxnic.commons.log.Logger;
import com.github.foxnic.dao.spec.DAO;
import com.github.foxnic.sql.expr.Insert;
import com.mysql.jdbc.log.Log;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * PingMonitor
 * 支持 Windows / macOS / Linux
 * IPv4 使用 ping，IPv6 使用 ping6
 * 支持每 summaryInterval 次输出一次统计
 */

public class MonitorDataProcessPingUtil {



    public boolean isEnableDb() {
        return enableDb;
    }

    public void setEnableDb(boolean enableDb) {
        this.enableDb = enableDb;
    }

    private boolean enableDb = true; // 默认不插数据库


    private MonitorTplIndicator indicator;


    private IMonitorTplTriggerService monitorTplTriggerService;

    public IMonitorTplTriggerService getMonitorTplTriggerService() {
        return monitorTplTriggerService;
    }

    public void setMonitorTplTriggerService(IMonitorTplTriggerService monitorTplTriggerService) {
        this.monitorTplTriggerService = monitorTplTriggerService;
    }


    public IMonitorAlertService getMonitorAlertService() {
        return monitorAlertService;
    }

    public void setMonitorAlertService(IMonitorAlertService monitorAlertService) {
        this.monitorAlertService = monitorAlertService;
    }

    private IMonitorAlertService monitorAlertService;




    public void setIsFailedByContinuousCount(int isFailedByContinuousCount) {
        this.isFailedByContinuousCount = isFailedByContinuousCount;
    }
    private int isFailedByContinuousCur = 0;
    private int isFailedByContinuousCount=3;
    String pingType;
    String ipAddress;
    int intervalSeconds=10;
    int totalCount=20;
    int summaryInterval=6;

    public MonitorNode getNode() {
        return node;
    }

    public void setNode(MonitorNode node) {
        this.node = node;
    }

    private MonitorNode node=null;
    public DAO getDao() {
        return dao;
    }

    public void setDao(DAO dao) {
        this.dao = dao;
    }

    private DAO dao=null;


    public MonitorTplIndicator getIndicator() {
        return indicator;
    }

    public void setIndicator(MonitorTplIndicator indicator) {
        this.indicator = indicator;
    }

    public int getIsFailedByContinuousCount() {
        return isFailedByContinuousCount;
    }

    public String getPingType() {
        return pingType;
    }

    public void setPingType(String pingType) {
        this.pingType = pingType;
    }

    public String getIpAddress() {
        return ipAddress;
    }

    public void setIpAddress(String ipAddress) {
        this.ipAddress = ipAddress;
    }

    public int getIntervalSeconds() {
        return intervalSeconds;
    }

    public void setIntervalSeconds(int intervalSeconds) {
        this.intervalSeconds = intervalSeconds;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getSummaryInterval() {
        return summaryInterval;
    }

    public void setSummaryInterval(int summaryInterval) {
        this.summaryInterval = summaryInterval;
    }

    private double formatStrToDouble(String value){
        if(StringUtil.isBlank(value)){
            value="0.00";
        }else{
            value=value.toString();
        }
        double res=0;
        res= Double.parseDouble(value);
        return Math.round(res * 100.0) / 100.0;
    }
    /**
     * 核心 Ping 方法
     */
    public boolean PingService() {
        String nodeName="";
        if(node!=null){
            nodeName=node.getNodeNameShow();
        }
        Logger.info("pingType:"+pingType
                +",nodeName:"+nodeName
                +",ipAddress:"+ipAddress
                +",intervalSeconds:"+intervalSeconds
                +",totalCount:"+totalCount
                +",summaryInterval:"+summaryInterval
                +",isFailedByContinuousCount:"+isFailedByContinuousCount
        );
        int successCount = 0;
        int failCount = 0;
        double totalDelay = 0;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String fromTime = sdf.format(new Date());

        int batchSuccess = 0;
        int batchFail = 0;

        double batchDelay = 0;
        String batchStartTime = fromTime;

        for (int seq = 1; seq <= totalCount; seq++) {
            String status = "failed";
            double delay = 0;
            String message = "";

            try {
                // === 构建命令 ===
                String os = System.getProperty("os.name").toLowerCase();
                String command;

                if (os.contains("win")) {
                    if ("pingV6".equalsIgnoreCase(pingType))
                        command = "ping -6 -n 1 " + ipAddress;
                    else
                        command = "ping -4 -n 1 " + ipAddress;
                } else {
                    if ("pingV6".equalsIgnoreCase(pingType))
                        command = "ping6 -c 1 " + ipAddress;
                    else
                        command = "ping -c 1 " + ipAddress;

                }

                ProcessBuilder pb;

                if (os.contains("win")) {
                    pb = new ProcessBuilder("cmd.exe", "/c", command);
                } else {
                    pb = new ProcessBuilder("/bin/sh", "-c", command);
                }
                pb.redirectErrorStream(true);
                Process process = pb.start();
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
                String line;
                boolean success = false;
                String lowerLine = "";
                while ((line = reader.readLine()) != null) {
                    lowerLine = line.toLowerCase();
                    //System.out.println("nodeName:"+node.getNodeNameShow()+",result:"+lowerLine);
                    // 检测成功
                    if (lowerLine.contains("time=") || lowerLine.contains("时间=")
                            || lowerLine.contains("bytes from") || lowerLine.contains("来自")) {
                        success = true;
                        // 提取延迟
                        int timeIndex = lowerLine.indexOf("time=");
                        if (timeIndex > 0) {

                            int msIndex = lowerLine.indexOf("ms", timeIndex);
                            if (msIndex > timeIndex) {
                                try {
                                    String delayStr = lowerLine.substring(timeIndex + 5, msIndex)
                                            .replace("ms", "").trim();
                                    delay =formatStrToDouble(delayStr);
                                } catch (Exception ignored) {
                                    ignored.printStackTrace();
                                }
                            }
                        } else if (lowerLine.contains("时间=")) {
                            int start = lowerLine.indexOf("时间=");
                            int end = lowerLine.indexOf("ms", start);
                            if (start > 0 && end > start) {
                                try {
                                    String delayStr = lowerLine.substring(start + 3, end)
                                            .replace("ms", "").trim();
                                    delay =formatStrToDouble(delayStr);
                                } catch (Exception ignored) {
                                    ignored.printStackTrace();
                                }
                            }
                        }
                    }
                    // 检测失败
                    if (lowerLine.contains("unreachable") || lowerLine.contains("timeout") || lowerLine.contains("请求超时")) {
                        message = "不可达。";
                    }
                }
                reader.close();
                process.waitFor();

                if (success) {
                    status = "success";
                    successCount++;
                    batchSuccess++;
                    totalDelay += delay;
                    batchDelay += delay;
                } else {
                    Logger.info("node:"+node.getNodeNameShow()+",ping failed,"+lowerLine);
                    failCount++;
                    batchFail++;
                    if (message.isEmpty()){
                        message = "不可达,明细:"+lowerLine;
                    }
                }

            } catch (Exception e) {
                failCount++;
                batchFail++;
                message = "执行错误：" + e.getMessage();

                if(enableDb){
                    Insert errInsert=new Insert("ops_monitor_node_value");
                    errInsert.set("id", IDGenerator.getSnowflakeId());
                    errInsert.setIf("result_status","failed");
                    errInsert.setIf("result_message",message);
                    errInsert.setIf("indicator_code",indicator.getCode());
                    errInsert.setIf("node_id",node.getId());
                    errInsert.setIf("is_connected",1);
                    errInsert.setIf("monitor_tpl_code",indicator.getMonitorTplCode());
                    errInsert.setIf("record_time",new Date());
                    dao.execute(errInsert);
                    return false;
                }
            }
            // === 控制台输出 ===
            String currentTime = sdf.format(new Date());
            System.out.printf("action:ping,time:%s,ip:%s,seq:%d,status:%s,delay(ms):%s%n",
                    currentTime, ipAddress, seq, status,delay,
                    status.equals("failed") ? ",msg=" + message : "");
            JSONObject statistics=new JSONObject();
            // === 每 summaryInterval 次输出统计 ===
            boolean reset=false;
            if (seq % summaryInterval == 0 || seq == totalCount) {
                String toTime = sdf.format(new Date());
                double successRate = (batchSuccess + batchFail) > 0
                        ? (batchSuccess * 100.0 / (batchSuccess + batchFail)) : 0.0;
                double avgDelay = batchSuccess > 0 ? (batchDelay * 1.0 / batchSuccess) : 0.0;
                System.out.printf("action:statistics,fromTime:%s,toTime:%s,success:%d,failed:%d,delay(ms):%.2f,successRate(%%):%.2f%n",
                        batchStartTime, toTime, batchSuccess, batchFail, avgDelay, successRate);
                if (enableDb) {
                    statistics.put("startTime",batchStartTime);
                    statistics.put("toTime",batchStartTime);
                    statistics.put("batchSuccess",batchSuccess);
                    statistics.put("batchFail",batchFail);
                    statistics.put("avgDelay",avgDelay);
                    statistics.put("successRate",successRate);
                }
                reset=true;
                // 重置批次计数
                batchStartTime = toTime;
                batchSuccess = 0;
                batchFail = 0;
                batchDelay = 0;
            }
            if (enableDb) {
                recordResult( "ping", currentTime, seq, delay, status, message,statistics.toJSONString());
            }
            try {
                Thread.sleep(intervalSeconds * 1000L);
            } catch (InterruptedException ignored) {}
        }

        return true;
    }

    // --- 模拟数据库记录 ---
    public boolean recordResult( String action, String time, long seq, double delay , String status, String msg,String statistics) {

        try {
            int isConnected=1;
            if(status.equals("failed")){
                isConnected=0;
                isFailedByContinuousCur++;
                Logger.info("node:"+node.getNodeNameShow()+",failed count(continuous):"+isFailedByContinuousCur+",maxCount:"+isFailedByContinuousCount);
                if(isFailedByContinuousCur>=isFailedByContinuousCount){
                    String tId=IDGenerator.getSnowflakeIdString();
                    Logger.info("node:"+node.getNodeNameShow()+",ping failed");
                    Insert ins=new Insert("ops_monitor_alert");
                    ins.setIf("id",tId);
                    ins.setIf("node_id",node.getId());
                    ins.setIf("status","not_confirm");
                    ins.setIf("trigger_id",indicator.getCode());
                    ins.setIf("warn_level","high");
                    ins.setIf("monitor_tpl_code",indicator.getMonitorTplCode());
                    ins.setIf("alert_value","failed");
                    ins.setIf("node_show_name",node.getNodeNameShow());
                    ins.setIf("trigger_name","网络不可达,指标:"+indicator.getCode());
                    ins.setIf("trigger_rule_desc","连续"+isFailedByContinuousCount+"次ping失败");
                    ins.setIf("warn_time",new Date());
                    ins.setIf("create_time",new Date());
                    dao.execute(ins);
                    monitorTplTriggerService.actionToAlert(monitorAlertService.getById(tId));
                    isFailedByContinuousCur=0;
                }
            }else{
                isFailedByContinuousCur=0;
            }
            //时间,序列,延迟,状态,原因,
            Insert valueInsert2=new Insert("ops_monitor_node_value_last");
            valueInsert2.set("id", IDGenerator.getSnowflakeId());
            valueInsert2.setIf("is_connected",isConnected);
            valueInsert2.setIf("code1",action);
            valueInsert2.setIf("list_value_str1",time);
            valueInsert2.setIf("value_int1",seq);
            valueInsert2.setIf("value_number1",delay);
            valueInsert2.setIf("value_str1",status);
            valueInsert2.setIf("value_str2",StringUtil.isBlank(msg)?"无":msg);
            valueInsert2.setIf("value_str3",statistics);
            valueInsert2.setIf("result_status","sucess");
            valueInsert2.setIf("result_message","执行成功");
            valueInsert2.setIf("indicator_code",indicator.getCode());
            valueInsert2.setIf("node_id",node.getId());
            valueInsert2.setIf("monitor_tpl_code",indicator.getMonitorTplCode());
            valueInsert2.setIf("record_time",new Date());
            valueInsert2.setIf("create_time",new Date());
            dao.pausePrintThreadSQL();
            dao.execute(valueInsert2);
            valueInsert2.into("ops_monitor_node_value");
            dao.execute(valueInsert2);
            dao.resumePrintThreadSQL();
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("数据库插入失败1：" + e.getMessage());
            return false;
        }
        return true;
    }

    // 测试入口
    public static void main(String[] args) {




        MonitorDataProcessPingUtil pm = new MonitorDataProcessPingUtil();
        pm.setEnableDb(false);
        pm.setIpAddress("101.35.255.17");
        pm.setPingType("pingV4");

//        pm.setIpAddress("::1");
//        pm.setPingType("pingV6");
        pm.setIntervalSeconds(1);
        pm.setSummaryInterval(2);
        pm.setTotalCount(5);
        pm.PingService();


    }
}
